条件表达式
我们会在后面的例子中使用下面的模型:
from django.db import models
class Client(models.Model):
REGULAR = 'R'
GOLD = 'G'
PLATINUM = 'P'
ACCOUNT_TYPE_CHOICES = (
(REGULAR, 'Regular'),
(GOLD, 'Gold'),
(PLATINUM, 'Platinum'),
)
name = models.CharField(max_length=50)
registered_on = models.DateField()
account_type = models.CharField(
max_length=1,
choices=ACCOUNT_TYPE_CHOICES,
)
class When(condition=None, then=None, **lookups)[source]
When()
对象用于封装条件和它的结果,为了在条件表达式中使用。使用When()
对象和使用filter()
方法类似。条件可以使用字段查找 或者 Q
来指定。结果通过使用then
关键字来提供。
一些例子:
要注意这些值中的每一个都可以是表达式。
>>> from django.db.models import Value
>>> When(then__exact=0, then=1)
>>> When(Q(then=0), then=1)
class Case(*cases, **extra)[source]
表达式就像是Python中的if ... elif ... else
语句。每个提供的When()
中的condition
按照顺序计算,直到得到一个真值。返回匹配When()
对象的result
表达式。
一个简单的例子:
Case()
接受任意数量的When()
对象作为独立的参数。其它选项使用关键字参数提供。如果没有条件为TRUE
,表达式会返回提供的default
关键字参数。如果没有提供default
参数,会使用Value(None)
。
如果我们想要修改之前的查询,来获取基于Client
跟着我们多长时间的折扣,我们应该这样使用查找:
>>> a_month_ago = date.today() - timedelta(days=30)
>>> a_year_ago = date.today() - timedelta(days=365)
>>> # Get the discount for each Client based on the registration date
>>> Client.objects.annotate(
... discount=Case(
... When(registered_on__lte=a_year_ago, then=Value('10%')),
... When(registered_on__lte=a_month_ago, then=Value('5%')),
... default=Value('0%'),
... output_field=CharField(),
... )
... ).values_list('name', 'discount')
[('Jane Doe', '5%'), ('James Smith', '0%'), ('Jack Black', '10%')]
高级查询
条件表达式可以用于注解、聚合、查找和更新。它们也可以和其它表达式混合和嵌套。这可以让你构造更强大的条件查询。
假设我们想要为客户端修改account_type
来匹配它们的注册日期。我们可以使用条件表达式和update()
放啊来实现:
如果我们想要弄清楚每个account_type
有多少客户端,要怎么做呢?我们可以在聚合函数中嵌套条件表达式来实现:
>>> # Create some more Clients first so we can have something to count
... name='Jean Grey',
... account_type=Client.REGULAR,
... registered_on=date.today())
>>> Client.objects.create(
... account_type=Client.PLATINUM,
... registered_on=date.today())
>>> Client.objects.create(
... name='Jane Porter',
... account_type=Client.PLATINUM,
... registered_on=date.today())
>>> # Get counts for each value of account_type
>>> from django.db.models import IntegerField, Sum
>>> Client.objects.aggregate(
... regular=Sum(
... Case(When(account_type=Client.REGULAR, then=1),
... output_field=IntegerField())
... ),
... gold=Sum(
... Case(When(account_type=Client.GOLD, then=1),
... output_field=IntegerField())
... ),
... platinum=Sum(
... Case(When(account_type=Client.PLATINUM, then=1),
... output_field=IntegerField())
... )
... )